package com.um.jdy.platform.financial.manager;


import cn.hutool.core.util.RandomUtil;
import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.um.jdy.common.finance.code.FinanceCode;
import com.um.jdy.common.finance.entity.po.MerchantBill;
import com.um.jdy.common.finance.entity.po.MerchantCashout;
import com.um.jdy.common.finance.entity.po.PlatformBill;
import com.um.jdy.common.finance.entity.po.PlatformProfitBill;
import com.um.jdy.common.finance.enums.FinancialEnum;
import com.um.jdy.common.finance.service.MerchantBillService;
import com.um.jdy.common.finance.service.MerchantCashoutService;
import com.um.jdy.common.finance.service.PlatformBillService;
import com.um.jdy.common.finance.service.PlatformProfitBillService;
import com.um.jdy.common.member.entity.po.MemberUser;
import com.um.jdy.common.member.enums.PayEnum;
import com.um.jdy.common.member.service.MemberUserService;
import com.um.jdy.common.platform.entity.po.Merchant;
import com.um.jdy.common.platform.service.MerchantService;
import com.um.jdy.common.commons.manager.WxManager;
import com.um.jdy.platform.financial.entity.dto.RejectDTO;
import com.um.jdy.platform.financial.entity.vo.BillSummaryVO;
import com.um.jdy.platform.financial.entity.vo.MerchantCashoutItemVO;
import com.um.jdy.platform.user.service.SessionUserService;
import com.um.springboot.starter.entity.Page;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.orm.entity.Response;
import com.um.springboot.starter.orm.manager.BaseManager;
import com.um.springboot.starter.orm.params.PageParams;
import com.um.springboot.starter.utils.OrderUtil;
import com.um.springboot.starter.utils.PayUtil;
import com.um.springboot.starter.utils.StringUtil;
import com.um.weixin.pay.service.WxTransferService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 管理类：商户提现表
 */
@Slf4j
@Component
public class MerchantCashoutManager extends BaseManager<MerchantCashoutService> {

    @Autowired
    SessionUserService sessionUserService;

    @Autowired
    PlatformBillService platformBillService;

    @Autowired
    MerchantBillService merchantBillService;

    @Autowired
    PlatformProfitBillService platformProfitBillService;

    @Autowired
    MemberUserService memberUserService;

    @Autowired
    WxTransferService wxTransferService;

    @Autowired
    WxManager wxManager;

    @Autowired
    MerchantService merchantService;

    /**
     * 分页查询运营商提现记录
     * @param pageParams
     * @return
     */
    public Response<Page<MerchantCashoutItemVO>> getCashoutPage(PageParams pageParams){
        Page<MerchantCashoutItemVO> page = new Page();
        page.setPageNo(pageParams.getPageNo());
        page.setPageSize(pageParams.getPageSize());

        pageParams.getCondition().put("a.com_id",getComId());
        pageParams.getCondition().put("me.type",pageParams.getCondition().get("type"));
        pageParams.getCondition().remove("type");

        page = service.getCMSViewModelPageBySqlName(page,"get_merchant_cashout_page","get_merchant_cashout_count",MerchantCashoutItemVO.class,
                pageParams.getProperties(),pageParams.getValues(),pageParams.getRangeEntitys(),pageParams.getOrderNames(),pageParams.getSortOns());

        page.setExtraData(this.getCashoutSummary(pageParams));
        return Response.success(page);
    }

    /**
     * 查询代理商提现统计结果
     *
     * @param pageParams
     * @return
     */
    private BillSummaryVO getCashoutSummary(PageParams pageParams) {

        BillSummaryVO entity = service.getCMSViewModelBySqlName("get_merchant_cashout_summary",BillSummaryVO.class,
                pageParams.getProperties(),pageParams.getValues(),pageParams.getRangeEntitys());
        return entity;
    }

    /**
     * 提现通过
     * @param id
     * @return
     */
    @Transactional
    public Response cashoutPass(String id){
        //修改提现状态
        MerchantCashout cashout = service.getEntity(id);
        if(null == cashout){
            throw new ServiceException(FinanceCode.CashoutExist);
        }

        if(!StringUtil.equals(cashout.getStatus(), FinancialEnum.CashoutStatus.Pending.name())){
            throw new ServiceException(FinanceCode.CashoutReviewed);
        }

        String outTradeNo = OrderUtil.getOrderNo();


        //TODO 需要判断余额是否足够
        //校验提现金额
        Integer canCashout = this.getTotalBalance(cashout.getPlatformMerchantId());
        Integer amount = cashout.getAmount();
        if(canCashout < amount){
            throw new ServiceException(FinanceCode.LowThanBalance);
        }

        //更新提现状态
        cashout.setStatus(FinancialEnum.CashoutStatus.Passed.name());
        cashout.setApproveTime(new Date());
        cashout.setApprover(sessionUserService.getTokenUserId());
        cashout.setOutTradeNo(outTradeNo);

        //提现到微信
        Integer cashAmount = cashout.getAmount() - cashout.getHandFee();
        Merchant merchant = merchantService.getEntity(cashout.getPlatformMerchantId());
        if(!PayUtil.isDev()) {

            if(PayEnum.CashOutType.Wxpay.name().equals(cashout.getType())){
                try {
                    //微信提现
                    wxManager.getPayService(merchant.getComId());
                    wxTransferService.transfer(merchant.getMpOpenId(), outTradeNo, PayUtil.toTotalFee(amount), "提现");
                } catch (WxPayException e) {
                    log.info("商家转账给用户错误-{}", e.newBuilder().buildErrorMsg());
                    throw new ServiceException(e.getErrCodeDes());
                }
                cashout.setStatus(FinancialEnum.CashoutStatus.PendingLoan.name());
            }

        }

        service.update(cashout);

        String status = PayEnum.CashOutType.Wxpay.name().equals(cashout.getType()) ?
                FinancialEnum.BillStatus.NotEffective.name() : FinancialEnum.BillStatus.Effective.name();

        //添加平台提现流水
        PlatformBill bill = new PlatformBill();
        bill.setOutTradeNo(outTradeNo);
        bill.setAmount(cashAmount);
        bill.setCreateTime(new Date());
        bill.setType(FinancialEnum.IncomeOrExpend.Expend.name());
        bill.setStatus(status);
        bill.setEvent(FinancialEnum.PlatformBillEvent.Cashout.name());
        bill.setNo(OrderUtil.getOrderNo());
        platformBillService.save(bill);

        //添加商户提现金额
        MerchantBill merchantBill = new MerchantBill();
        merchantBill.setOutTradeNo(outTradeNo);
        merchantBill.setAmount(cashAmount);
        merchantBill.setCreateTime(new Date());
        merchantBill.setType(FinancialEnum.IncomeOrExpend.Expend.name());
        merchantBill.setStatus(status);
        merchantBill.setEvent(FinancialEnum.MerchantBillEvent.Cashout.name());
        merchantBill.setNo(OrderUtil.getOrderNo());
        merchantBill.setComId(cashout.getComId());
        merchantBill.setPlatformMerchantId(cashout.getPlatformMerchantId());
        merchantBillService.save(merchantBill);


        //添加商户提现手续费
        MerchantBill handBill = new MerchantBill();
        handBill.setOutTradeNo(outTradeNo);
        handBill.setAmount(cashout.getHandFee());
        handBill.setCreateTime(new Date());
        handBill.setType(FinancialEnum.IncomeOrExpend.Expend.name());
        handBill.setStatus(status);
        handBill.setNo(OrderUtil.getOrderNo());
        handBill.setEvent(FinancialEnum.MerchantBillEvent.HandFee.name());
        handBill.setComId(cashout.getComId());
        handBill.setPlatformMerchantId(cashout.getPlatformMerchantId());
        merchantBillService.save(handBill);


        //添加平台收益流水
        PlatformProfitBill profitBill = new PlatformProfitBill();
        profitBill.setOutTradeNo(outTradeNo);
        profitBill.setAmount(cashout.getHandFee());
        profitBill.setCreateTime(new Date());
        profitBill.setType(FinancialEnum.IncomeOrExpend.Income.name());
        profitBill.setStatus(status);
        profitBill.setEvent(FinancialEnum.PlatformProfitBillEvent.HandFee.name());
        profitBill.setNo(OrderUtil.getOrderNo());
        platformProfitBillService.save(profitBill);

        return Response.success();
    }

    /**
     * 提现拒绝
     * @param rejectDTO
     * @return
     */
    public Response cashoutReject(String id, RejectDTO rejectDTO){
        //修改提现状态
        MerchantCashout cashout = service.getEntity(id);

        if(null == cashout){
            throw new ServiceException(FinanceCode.CashoutExist);
        }

        cashout.setApproveTime(new Date());
        cashout.setApprover(sessionUserService.getTokenUserId());
        cashout.setStatus(FinancialEnum.CashoutStatus.Rejected.name());
        cashout.setRejectReason(rejectDTO.getReason());
        boolean result = service.update(cashout);
        return result ? Response.success() : Response.failed();
    }


    /**
     * 总余额（包括提现待审核的）
     * @return
     */
    public Integer getTotalBalance(String merchantId){
        return getTotalIncome(merchantId) - getTotalExpend(merchantId);
    }

    /**
     * 账单总收入
     * @return
     */
    public Integer getTotalIncome(String merchantId){
        Long income =  service.getCountBySqlName("get_merchant_total_income",new Object[]{getComId(),merchantId});
        return income.intValue();
    }

    /**
     * 账单总支出
     * @return
     */
    public Integer getTotalExpend(String merchantId){
        Long income =  service.getCountBySqlName("get_merchant_total_expend",new Object[]{getComId(),merchantId});
        return income.intValue();
    }

    /**
     * 累计提现（提现金额）
     * @return
     */
    public Integer getTotalCashout(String merchantId){
        Long income =  service.getCountBySqlName("get_merchant_total_cash_out",new Object[]{getComId(),merchantId});
        return income.intValue();
    }

}
